package com.spring.picture.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;

import java.util.*;
import java.util.stream.Collectors;

@Component
public class RedisHotKeyDetector {

    @Autowired
    private JedisPool jedisPool; // 直接使用 Jedis 执行原生命令（比 RedisTemplate 更灵活）

    private static final String HOT_KEY_COUNTER = "hot_key:counter"; // 存储热键计数的 Redis 键（哈希结构）
    private static final int SCAN_BATCH_SIZE = 1000; // 每次扫描的键数量

    /**
     * 业务代码中每次访问键时调用（需业务集成）
     * @param key 被访问的键
     */
    public void recordKeyAccess(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.hincrBy(HOT_KEY_COUNTER, key, 1); // 原子性增加计数
            jedis.expire(HOT_KEY_COUNTER, 3600); // 计数数据有效期 1 小时（可配置）
        }
    }

    /**
     * 定时检测热键（每60秒执行，fixedRate单位毫秒）
     */
    @Scheduled(fixedRate = 60000)
    public void detectHotKeys() {
        List<Map.Entry<String, Long>> hotKeys = new ArrayList<>();

        try (Jedis jedis = jedisPool.getResource()) {
            // 1. 获取所有键的访问计数（按分数降序排序）
            Map<String, String> counterMap = jedis.hgetAll(HOT_KEY_COUNTER);
            if (counterMap.isEmpty()) {
                return;
            }

            // 2. 转换为键-计数对，并按计数排序
            hotKeys = counterMap.entrySet().stream()
                .map(entry -> new AbstractMap.SimpleEntry<>(entry.getKey(), Long.parseLong(entry.getValue())))
                .sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue()))
                .limit(5) // 取前 5 名热键
                .collect(Collectors.toList());

            // 3. 清空计数（或保留历史数据，按需设计）
            jedis.del(HOT_KEY_COUNTER);
        }

        // 打印热键信息
        hotKeys.forEach(entry -> 
            System.out.println("Hot Key Detected: " + entry.getKey() + ", Access Count: " + entry.getValue())
        );
    }

    /**
     * 辅助方法：扫描所有键（用于初始化或全量统计，谨慎在生产环境使用）
     */
    private void scanAllKeys() {
        try (Jedis jedis = jedisPool.getResource()) {
            String cursor = "0";
            do {
                ScanParams params = new ScanParams().count(SCAN_BATCH_SIZE);
                ScanResult<String> scanResult = jedis.scan(cursor, params);
                List<String> keys = scanResult.getResult();
                cursor = scanResult.getCursor();

                // 对每个键增加计数（需结合业务逻辑，避免无意义的键被统计）
                keys.forEach(key -> recordKeyAccess(key));
            } while (!"0".equals(cursor));
        }
    }
}